/*
 * tcp_port.c
 *
 *  Created on: 2012-6-7
 *      Author: Administrator
 */


#include "tcp_port.h"
#include "port.h"
#include "luas.h"
#include "channel/unix_socket.h"
#include "pkt.h"
#include "msgdef.h"


static int port_on_packet(int portfd, int linefd, int msgid, int pktfd)
{
	js_sys("tcp_port", "port_on_packet\n");

    int unix_sock_fd = (int)port_get_userdata(portfd);
    js_sys("tcp_port", "unix_sock_fd is :%d\n", unix_sock_fd);
    if(!unix_socket_is_connectted(unix_sock_fd)){
    	js_sys("tcp_port", "channel is not connectted!\n");
    	return;
    }
    int buffd = unix_socket_get_write_buffd(unix_sock_fd);
    int pkt_buffd = pkt2buffd(pktfd);
    int body_len = pkt2bodylen(pktfd);

    cbuf_write_int(buffd, body_len + 16);
    cbuf_write_int(buffd, MSG_TCP_PORT_SEND_MSG);
    cbuf_write_int(buffd, linefd);
    cbuf_write_int(buffd, pkt2msgid(pktfd));
    //cbuf_write_utf(buffd, "hello");
    js_sys("tcp_port", "playload len:%d\n", body_len);
    cbuf_write_cbuf(buffd, pkt_buffd, body_len);
    cbuf_info(buffd); 
    //
   // unix_socket_write(unix_sock_fd, MSG_TCP_PORT_SEND_MSG);
  //  unix_socket_transmit()
}
static int port_on_close(int portfd, int linefd){
	js_sys("tcp_port", "port_on_close\n");
	int unix_socket_fd = (int)port_get_userdata(portfd);
	int buffd = unix_socket_get_write_buffd(unix_socket_fd);
	cbuf_write_int(buffd, 12);
	cbuf_write_int(buffd, MSG_TCP_PORT_CLOSE_LINE);
	cbuf_write_int(buffd, linefd);
	return 1;
}
static int port_on_accept(int portfd, int sockfd)
{
	js_sys("tcp_port", "port_on_accept\n");

    int unix_socket_fd = (int)port_get_userdata(portfd);
    if(!unix_socket_is_connectted(unix_socket_fd)){
    	js_sys("tcp_port", "channel is not connectted! reject!\n");
    	port_reject(portfd, sockfd);
        return 1;
    }
    //TODO
    //有个问题.如果LUA那边即不ACCEPT, 也不REJECT,那么由于sockfd还没加入事件队列,
    //所以收不到read事件,就不能关闭sock了
    js_sys("tcp_port", "notify module a client connectted\n");
    int buffd = unix_socket_get_write_buffd(unix_socket_fd);
    cbuf_write_int(buffd, 12);
    cbuf_write_int(buffd, MSG_TCP_PORT_NEW_CLIENT);
    cbuf_write_int(buffd, sockfd);
    return 1;
}

static int channel_on_packet(int unix_socket_fd, int msgid, int pktfd)
{
    js_sys("tcp_port", "channel_on_packet\n");
    int portfd = (int)unix_socket_get_userdata(unix_socket_fd);
    int buffd = unix_socket_get_write_buffd(unix_socket_fd);
    switch(msgid){
    	case MSG_TCP_PORT_ACCEPT_CLIENT:{
    		int sockfd = pkt_read_int(pktfd);
    		js_sys("tcp_port", "accept sock fd:%d!\n", sockfd);
    		int linefd = port_accept(portfd, sockfd);
    		js_sys("tcp_port", "build line fd:%d!\n", linefd);
    		cbuf_write_int(buffd, 12);
    		cbuf_write_int(buffd, MSG_TCP_PORT_NEW_LINE);
    		cbuf_write_int(buffd, linefd);
    	}
    	break;
    	case MSG_TCP_PORT_REJECT_CLIENT:{
    		int sockfd = pkt_read_int(pktfd);
    		port_reject(portfd, sockfd);
    		js_sys("tcp_port", "reject sock fd:%d!\n", sockfd);
    	}
    	break;
    	case MSG_TCP_PORT_SEND_MSG:{
            
    		int linefd = pkt_read_int(pktfd);
    		if(line_is_close(linefd)){
    			js_sys("tcp_port", "line:%d is closed, skip packet\n", linefd);
    			return;
    		}
    		int buffd = line_get_write_buffd(linefd);
    		int body_len = pkt2bodylen(pktfd);

            js_sys("tcp_port", "send msg playload len:%d\n", body_len);
    		cbuf_write_int(buffd, body_len);
    		cbuf_write_cbuf(buffd, pkt2buffd(pktfd), body_len - 4);
    	}break;
    }
    return 1;
}


static int tcp_port_set_channel(int portfd, int unix_socket_fd){

	js_sys("tcp_port", "tcp_port_set_channel\n");
	js_sys("tcp_port", "unix_sock_fd is :%d\n", unix_socket_fd);
	unix_socket_set_cb_packet(unix_socket_fd, channel_on_packet);
	unix_socket_set_userdata(unix_socket_fd, (void*)portfd);
	port_set_userdata(portfd, (void*)unix_socket_fd);
	return 0;
}

int tcp_port_new()
{
    int portfd = port_new();

    port_set_userdata(portfd, (void *)0);
    port_set_cb_accept(portfd, port_on_accept);
    port_set_cb_close(portfd, port_on_close);
    port_set_cb_packet(portfd, port_on_packet);
    return portfd;
}


static int NewPort(lua_State *L)
{
    if (LUA_ARGNUM == 0)
    {
        int portfd = tcp_port_new();
        LUA_RETURN(portfd);
    }
    LUA_RETURN(-1);
}

static int SetChannel(lua_State *L)
{
    if (LUA_ARGNUM == 2 && LUA_ISNUMBER(1) && LUA_ISNUMBER(2))
    {
        int portfd = (int)LUA_TONUMBER(1);
        int channelfd = (int)LUA_TONUMBER(2);

        int rt = tcp_port_set_channel(portfd, channelfd);
        LUA_RETURN(rt);
    }
    LUA_RETURN(-1);
}

static luaL_Reg lua_lib[] =
{
	LUA_FUNC_INIT(NewPort),
	LUA_FUNC_INIT(SetChannel),
    {NULL, NULL}
};

int tcp_port_init()
{
	luas_reg_lib("TCPPort", lua_lib);
}
